/*******************************************************************************
  MPLAB Harmony Application Source File
  
  Company:
    Microchip Technology Inc.
  
  File Name:
    app5.c

  Summary:
    This file contains the source code for the MPLAB Harmony application.

  Description:
    This file contains the source code for the MPLAB Harmony application.  It 
    implements the logic of the application's state machine and it may call 
    API routines of other MPLAB Harmony modules in the system, such as drivers,
    system services, and middleware.  However, it does not call any of the
    system interfaces (such as the "Initialize" and "Tasks" functions) of any of
    the modules in the system or make any assumptions about when those functions
    are called.  That is the responsibility of the configuration-specific system
    files.
 *******************************************************************************/

// DOM-IGNORE-BEGIN
/*******************************************************************************
Copyright (c) 2013-2014 released Microchip Technology Inc.  All rights reserved.

Microchip licenses to you the right to use, modify, copy and distribute
Software only when embedded on a Microchip microcontroller or digital signal
controller that is integrated into your product or third party product
(pursuant to the sublicense terms in the accompanying license agreement).

You should refer to the license agreement accompanying this Software for
additional information regarding your rights and obligations.

SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER
CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR
OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR
CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF
SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
 *******************************************************************************/
// DOM-IGNORE-END


// *****************************************************************************
// *****************************************************************************
// Section: Included Files 
// *****************************************************************************
// *****************************************************************************

#include "app4.h"
#include "app5.h"

#include "pcf8575.h"
#include "ad5620.h"
#include "app4.h"
#include "user_config.h"

extern APP4_DATA app4Data;

// *****************************************************************************
// *****************************************************************************
// Section: Global Data Definitions
// *****************************************************************************
// *****************************************************************************

// *****************************************************************************
/* Application Data

  Summary:
    Holds application data

  Description:
    This structure holds the application's data.

  Remarks:
    This structure should be initialized by the APP_Initialize function.
    
    Application strings and buffers are be defined outside this structure.
 */

APP5_DATA app5Data;

uint8_t app5_send_buff[256];
uint8_t app5_recv_buff[256];

uint16_t bootloader_save_buff[512] = {0}; 		/*将参数保存的FLASH的缓存区。*/  /*FLASH按照WORD为单位来写。*/
uint16_t bootloader_save_temp[256] = {0};
extern OS_SEM   freq_ctrl_sem; //远程控制AO输出信号量。 
extern APP4_DATA app4Data;
extern uint16_t ADCValue_1;
extern uint32_t timer_value;
extern uint32_t moment_value;

extern void load_motor_cfg_tbl(void);
// *****************************************************************************
// *****************************************************************************
// Section: Application Callback Functions
// *****************************************************************************
// *****************************************************************************

/* TODO:  Add any necessary callback funtions.
 */

// *****************************************************************************
// *****************************************************************************
// Section: Application Local Functions
// *****************************************************************************
// *****************************************************************************

/* TODO:  Add any necessary local functions.
 */

/* Table of CRC values for high-order byte */
static uint8_t table_crc_hi[] = {
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
    0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
    0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
    0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
    0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
};

/* Table of CRC values for low-order byte */
static uint8_t table_crc_lo[] = {
    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
    0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
    0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
    0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
    0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
    0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
    0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
    0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
    0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
    0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
    0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
    0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
    0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
    0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
    0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
    0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
    0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
    0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
    0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
    0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
    0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
    0x43, 0x83, 0x41, 0x81, 0x80, 0x40
};

unsigned int NVMUnlock(unsigned int nvmop) {
    unsigned int status = 0;
    // Suspend or Disable all Interrupts
    asm volatile ("di %0" : "=r" (status));
    // Enable Flash Write/Erase Operations and Select
    // Flash operation to perform
    NVMCON = NVMCON_WREN | nvmop;

    // wait at least 6 us for LVD start-up
    // assume we're running at max frequency
    // (80 MHz) so we're always safe
    {
        unsigned long t0 = _CP0_GET_COUNT();
        while (_CP0_GET_COUNT() - t0 < (80 / 2)*6);
    }

    // Write Keys
    NVMKEY = 0xAA996655;
    NVMKEY = 0x556699AA;
    // Start the operation using the Set Register
    NVMCONSET = 0x8000;
    // Wait for operation to complete
    while (NVMCON & 0x8000);
    // Disable NVM write enable
    NVMCONCLR = 0x0004000;
    // Restore Interrupts
    if (status & 0x00000001) {
        asm volatile ("ei");
    } else {
        asm volatile ("di");
    }

    // Return WRERR and LVDERR Error Status Bits
    return (NVMCON & 0x3000);
}

unsigned int NVMErasePage(void* address) {
    unsigned int res;
    // Set NVMADDR to the Start Address of page to erase
    NVMADDR = (unsigned int) address;
    // Unlock and Erase Page
    res = NVMUnlock(0x4004);
    // Return Result
    return res;
}

unsigned int NVMWriteRow(void* address, void* data) {
    unsigned int res;
    // Set NVMADDR to Start Address of row to program
    NVMADDR = (unsigned int) address;
    // Set NVMSRCADDR to the SRAM data buffer Address
    NVMSRCADDR = (unsigned int) data;
    // Unlock and Write Row
    res = NVMUnlock(0x4003);
    // Return Result
    return res;
}

unsigned int NVMWriteWord(void* address, unsigned int data) {
    unsigned int res;
    // Load data into NVMDATA register
    NVMDATA = data;
    // Load address to program into NVMADDR register
    NVMADDR = (unsigned int) address;
    // Unlock and Write Word
    res = NVMUnlock(0x4001);
    // Return Result
    return res;
}

unsigned int NVMClearError(void) {
    unsigned int res;
    // Unlock and Write Word
    res = NVMUnlock(0x4000);
    // Return Result
    return res;
}

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  NVMReadRow
 *  Description:  从FLASH中读取一行数据。
 * =====================================================================================
 */
void NVMReadRow(void* addr, uint16_t *data) {

    uint16_t i;

    for (i = 0; i < 256; i += 1) { /*从FLASH中读取参数到配置信息表中。*/
        data[i] = *(uint16_t *) ((unsigned int) addr + i * 2);
    }

    return;
} /* -----  end of function NVMReadRow  ----- */

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  NVMReadWord
 *  Description:
 * =====================================================================================
 */
uint16_t NVMReadWord(void* addr) {

    return *(uint16_t *) ((unsigned int) addr);
} /* -----  end of function NVMReadWord  ----- */

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  count_crc16
 *  Description:  计算CRC校验码
 * =====================================================================================
 */
uint16_t count_crc16(uint8_t *query, uint16_t query_length) {

    uint8_t crc_hi = 0xFF; /* high CRC byte initialized */
    uint8_t crc_lo = 0xFF; /* low CRC byte initialized */
    uint16_t i; /* will index into CRC lookup */

    /* pass through message buffer */
    while (query_length--) {
        i = crc_hi ^ *query++; /* calculate the CRC  */
        crc_hi = crc_lo ^ table_crc_hi[i];
        crc_lo = table_crc_lo[i];
    }

    return (crc_hi << 8 | crc_lo);
} /* -----  end of static function count_crc16  ----- */

/* If CRC is correct returns 0 else returns INVALID_CRC */
uint16_t check_crc16(uint8_t *msg, const uint16_t msg_length) {

    uint16_t crc_calc;
    uint16_t crc_received;

    crc_calc = count_crc16(msg, msg_length - 2);
    crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];

    /* Check CRC of msg */
    if (crc_calc == crc_received) {
        return true;
    } else {
        return false;
    }
}

//KSEG0 虚拟地址 = 物理地址 | 0x80000000

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  device_save_reboot
 *  Description:
 * =====================================================================================
 */
void device_save_reboot(void) {

    uint16_t i;
    uint16_t ret;

    ret = NVMErasePage((void*) (0x1d07f000 | 0xa0000000));
    //	ret = NVMErasePage((void*)0xBD010000);
    //	delay_W5100(1000);
    for (i = 0; i < 100; i++) {
        ret = NVMWriteWord((void*) ((0x1d07f000 | 0xa0000000) + i * 4), cfg_tbl_temp[i]);
        if (ret != 0) {
            printf("Save Param Error![addr = %ld]\r\n", ((0x1d07f000 | 0xa0000000) + i * 4));
        }
    }
    printf("Save Param Finish, Reset Now!!!\r\n");
    SoftReset(); //软件复位
    return;
} /* -----  end of function device_save_reboot  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  save_cfg_para
 *  Description:  保存配置信息表的FM24W256。
 * =====================================================================================
 */
void save_cfg_para(uint8_t reset_flag) {

    uint16_t i;
    uint16_t j;
    uint16_t addr = 0;
    uint8_t save_temp[16] = {0};
    uint8_t flag[16];
    OS_ERR os_err;

    for (i = 0; i < 8; i += 1) { //写入标准位。
        flag[i] = 0x77;
    }
    OSTimeDly(5, OS_OPT_TIME_DLY, &os_err);
    page_write_E2PROM(0xAE, 0x01, 0x00, flag, 16);

    for (i = 0; i < 8; i += 1) {
        for (j = 0; j < 8; j += 1) {
            save_temp[j * 2] = ((cfg_tbl_temp[i * 8 + j] >> 8) & 0x00ff);
            save_temp[j * 2 + 1] = (cfg_tbl_temp[i * 8 + j] & 0x00ff);
        }
        page_write_E2PROM(0xae, 0x00, addr + i * 16, save_temp, 16);
        OSTimeDly(5, OS_OPT_TIME_DLY, &os_err);
    }

    OSTimeDly(5, OS_OPT_TIME_DLY, &os_err);
    page_write_E2PROM(0xAE, 0x01, 0x08, flag, 16);

    if (reset_flag == 1) {
        PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
        printf("Save Param Finish, Reset Now!!!\r\n");
        PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
        SoftReset(); //软件复位
    }
    return;
} /* -----  end of function save_cfg_para  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  set_calibration_value
 *  Description:  
 * =====================================================================================
 */
void set_calibration_value(uint16_t data){

	ad5620_data_send(&ad5620_para, data);
	mcp4161_data_send(&mcp4161_para, data);

	return ;
}		/* -----  end of function set_calibration_value  ----- */

void save_cal_para(void){

    uint16_t addr;
    uint8_t temp[32] = {0};
    uint16_t j;
    uint8_t save_temp[32] = {0};
    OS_ERR os_err;

    for (j = 0; j < 16; j += 1) {
        save_temp[j * 2] = ((cal_para[j] >> 8) & 0x00ff);
        save_temp[j * 2 + 1] = (cal_para[j] & 0x00ff);
    }

    save_temp[30] = 0xff;
    save_temp[31] = 0x00;   //校准有效标志位

    page_write_E2PROM(0xAE, 0x00, (0x0100 - 32), &save_temp[0], 16);
    OSTimeDly(5, OS_OPT_TIME_DLY, &os_err);
    page_write_E2PROM(0xAE, 0x00, (0x0100 - 16), &save_temp[16], 16);
//    OSTimeDly(5, OS_OPT_TIME_DLY, &os_err);
//    addr = 0x0100 - 32;
//
//	read_conitue(0xAE, ((addr >> 8) & 0x00ff), ((addr >> 0) & 0x00ff), &temp[0], 16);
//	addr = 0x0100 - 16;    		//地址0x0100用于判断eeprom数据是否正常。 -16用于存储校准信息。
//	read_conitue(0xAE, ((addr >> 8) & 0x00ff), ((addr >> 0) & 0x00ff), &temp[16], 16);


    PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
    printf("Save Cal Param Finish, Reset Now!!!\r\n");
    PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
    SoftReset(); //软件复位
}

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  fun_03_analy
 *  Description:
 * =====================================================================================
 */
void fun_03_analy(uint16_t chn, uint16_t reg_addr, uint16_t reg_numb) {

    uint16_t i;
    uint16_t index = 0;
    uint16_t crc_code = 0;

    /*读取配置信息表*/
    if ((reg_addr >= CFG_TBL_START_ADDR) && ((reg_addr + reg_numb) <= (CFG_TBL_END_ADDR + 1))) {
        app5_send_buff[index++] = 0x01;
        app5_send_buff[index++] = 0x03;
        app5_send_buff[index++] = reg_numb * 2;
        for (i = 0; i < reg_numb; i += 1) {
            app5_send_buff[index++] = (cfg_tbl[reg_addr - CFG_TBL_START_ADDR + i] >> 8) & 0x00ff;
            app5_send_buff[index++] = cfg_tbl[reg_addr - CFG_TBL_START_ADDR + i] & 0x00ff;
        }
        crc_code = count_crc16(app5_send_buff, index);
        app5_send_buff[index++] = (crc_code >> 8) & 0x00ff;
        app5_send_buff[index++] = crc_code & 0x00ff;
        DRV_USART0_Send(app5_send_buff, index);
        pcf8575_led_toggle(LED_LO_05);
        //                switch(chn){
        //                    case 0:
        //                        DRV_USART0_Send(app5_send_buff, index);
        //                        break;
        //                    case 1:
        //                         DRV_USART1_Send(app5_send_buff, index);
        //                        break;
        //                }
    }

    /*读取测量信息表*/
    if ((reg_addr >= MES_TBL_START_ADDR) && ((reg_addr + reg_numb) <= (MES_TBL_END_ADDR + 1))) {
        app5_send_buff[index++] = 0x01;
        app5_send_buff[index++] = 0x03;
        app5_send_buff[index++] = reg_numb * 2;
        for (i = 0; i < reg_numb; i += 1) {
            app5_send_buff[index++] = (mes_tbl[reg_addr - MES_TBL_START_ADDR + i] >> 8) & 0x00ff;
            app5_send_buff[index++] = mes_tbl[reg_addr - MES_TBL_START_ADDR + i] & 0x00ff;
        }
        crc_code = count_crc16(app5_send_buff, index);
        app5_send_buff[index++] = (crc_code >> 8) & 0x00ff;
        app5_send_buff[index++] = crc_code & 0x00ff;
        DRV_USART0_Send(app5_send_buff, index);
        pcf8575_led_toggle(LED_LO_05);
        //                switch(chn){
        //                    case 0:
        //                        DRV_USART0_Send(app5_send_buff, index);
        //                        break;
        //                    case 1:
        //                         DRV_USART1_Send(app5_send_buff, index);
        //                        break;
        //                }
    }

    /*读取校准信息表*/
    if ((reg_addr >= 0x3000) && ((reg_addr + reg_numb) <= (0x3010 + 1))) {
        app5_send_buff[index++] = 0x01;
        app5_send_buff[index++] = 0x03;
        app5_send_buff[index++] = reg_numb * 2;
        for (i = 0; i < reg_numb; i += 1) {
            app5_send_buff[index++] = (cal_para[reg_addr - 0x3000 + i] >> 8) & 0x00ff;
            app5_send_buff[index++] = cal_para[reg_addr - 0x3000 + i] & 0x00ff;
        }
        crc_code = count_crc16(app5_send_buff, index);
        app5_send_buff[index++] = (crc_code >> 8) & 0x00ff;
        app5_send_buff[index++] = crc_code & 0x00ff;
        DRV_USART0_Send(app5_send_buff, index);
        pcf8575_led_toggle(LED_LO_05);
        //                switch(chn){
        //                    case 0:
        //                        DRV_USART0_Send(app5_send_buff, index);
        //                        break;
        //                    case 1:
        //                         DRV_USART1_Send(app5_send_buff, index);
        //                        break;
        //                }
    }

    return;
} /* -----  end of function fun_03_analy  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  fun_05_analy
 *  Description:  
 * =====================================================================================
 */
void fun_05_analy(uint16_t chn, uint16_t reg_addr, uint16_t reg_numb){

	uint16_t index = 0;
	uint16_t crc_code = 0;
         OS_ERR os_err;

	  if((reg_numb == 0xFF00) && (reg_addr == 0x1000)){ //电机检测程序，测试命令
                app5_send_buff[index++] = 0x01;
		app5_send_buff[index++] = 0x05;
		app5_send_buff[index++] = (reg_addr >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_addr >> 0) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 0) & 0x00ff;
		crc_code = count_crc16(app5_send_buff, index);
		app5_send_buff[index++] = (crc_code >> 8) & 0x00ff;
		app5_send_buff[index++] = crc_code & 0x00ff;
		DRV_USART0_Send(app5_send_buff, index);
		pcf8575_led_toggle(LED_LO_05);
	}
	
        if((reg_numb == 0xFF00) && (reg_addr == 0x1001)){ //电机检测程序，启动命令
                app5_send_buff[index++] = 0x01;
		app5_send_buff[index++] = 0x05;
		app5_send_buff[index++] = (reg_addr >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_addr >> 0) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 0) & 0x00ff;
		crc_code = count_crc16(app5_send_buff, index);
		app5_send_buff[index++] = (crc_code >> 8) & 0x00ff;
		app5_send_buff[index++] = crc_code & 0x00ff;
		DRV_USART0_Send(app5_send_buff, index);
		pcf8575_led_toggle(LED_LO_05);

		switch(cfg_tbl[0x0000]){
			case 0x0000:	
				timer_value = 0;
				moment_value = 0;
				app4Data.state = MODEL_1;
				break;
			case 0x0001:	
				timer_value = 0;
				moment_value = 0;
				app4Data.state = MODEL_2;
				break;
			case 0x0002:	
				timer_value = 0;
				moment_value = 0;
				app4Data.state = MODEL_3;
				break;
			default:	
				break;
		}				/* -----  end switch  ----- */

	}
	
        if((reg_numb == 0xFF00) && (reg_addr == 0x1002)){ //电机检测程序，停止命令
                app5_send_buff[index++] = 0x01;
		app5_send_buff[index++] = 0x05;
		app5_send_buff[index++] = (reg_addr >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_addr >> 0) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 0) & 0x00ff;
		crc_code = count_crc16(app5_send_buff, index);
		app5_send_buff[index++] = (crc_code >> 8) & 0x00ff;
		app5_send_buff[index++] = crc_code & 0x00ff;
		DRV_USART0_Send(app5_send_buff, index);
		pcf8575_led_toggle(LED_LO_05);
		timer_value = 0;
		moment_value = 0;
		app4Data.state = MODEL_IDLE;
	}
	
        if((reg_numb == 0xFF00) && (reg_addr == 0x4001)){ //切换到备通道
                cfg_tbl[CFG_OFS_AO_CHANNEL] = 0x01;
                app5_send_buff[index++] = 0x01;
		app5_send_buff[index++] = 0x05;
		app5_send_buff[index++] = (reg_addr >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_addr >> 0) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 0) & 0x00ff;
		crc_code = count_crc16(app5_send_buff, index);
		app5_send_buff[index++] = (crc_code >> 8) & 0x00ff;
		app5_send_buff[index++] = crc_code & 0x00ff;
		DRV_USART0_Send(app5_send_buff, index);
                pcf8575_led_on(LED_HI_06);
		pcf8575_led_toggle(LED_LO_05);
        }
        if((reg_numb == 0x0000) && (reg_addr == 0x4001)){ //切换到主通道
                cfg_tbl[CFG_OFS_AO_CHANNEL] = 0x00;
                app5_send_buff[index++] = 0x01;
		app5_send_buff[index++] = 0x05;
		app5_send_buff[index++] = (reg_addr >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_addr >> 0) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 0) & 0x00ff;
		crc_code = count_crc16(app5_send_buff, index);
		app5_send_buff[index++] = (crc_code >> 8) & 0x00ff;
		app5_send_buff[index++] = crc_code & 0x00ff;
		DRV_USART0_Send(app5_send_buff, index);
                pcf8575_led_off(LED_HI_06);
		pcf8575_led_toggle(LED_LO_05);
        }

	if((reg_numb == 0xFF00) && (reg_addr == 0x4000)){ //进入校准模式
		app5_send_buff[index++] = 0x01;
		app5_send_buff[index++] = 0x05;
		app5_send_buff[index++] = (reg_addr >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_addr >> 0) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 0) & 0x00ff;
		crc_code = count_crc16(app5_send_buff, index);
		app5_send_buff[index++] = (crc_code >> 8) & 0x00ff;
		app5_send_buff[index++] = crc_code & 0x00ff;
		DRV_USART0_Send(app5_send_buff, index);
		pcf8575_led_toggle(LED_LO_05);
         
		app4Data.state = APP_STATE_CALBRITION; /*让task4进入校准模式*/
		OSAL_SEM_Post(&freq_ctrl_sem); /*发送接收完成的信号量*/
	}
	if((reg_numb == 0x0000) && (reg_addr == 0x4000)){ //退出校准模式
		app5_send_buff[index++] = 0x01;
		app5_send_buff[index++] = 0x05;
		app5_send_buff[index++] = (reg_addr >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_addr >> 0) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 0) & 0x00ff;
		crc_code = count_crc16(app5_send_buff, index);
		app5_send_buff[index++] = (crc_code >> 8) & 0x00ff;
		app5_send_buff[index++] = crc_code & 0x00ff;
		DRV_USART0_Send(app5_send_buff, index);
		pcf8575_led_toggle(LED_LO_05);
                OSTimeDly (300, OS_OPT_TIME_DLY, &os_err);
                save_cal_para();
	}

	return ;
}		/* -----  end of function fun_05_analy  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  fun_06_analy
 *  Description:  
 * =====================================================================================
 */
void fun_06_analy(uint16_t chn, uint16_t reg_addr, uint16_t reg_numb){

	uint16_t index = 0;
	uint16_t crc_code = 0;

	if((reg_addr >= 0x3000) && (reg_addr <= 0x3010)){
		switch(reg_addr){
			case 0x3004:	 /*AI下限校准*/ 
				cal_para[0x0004] = ADCValue_1;
				break;
			case 0x3005:	 /*AI上限校准*/ 
				cal_para[0x0005] = ADCValue_1;
				break;
			default:	
				cal_para[reg_addr - 0x3000] = reg_numb;
				set_calibration_value(reg_numb);
				break;
		}				/* -----  end switch  ----- */
		app5_send_buff[index++] = 0x01;
		app5_send_buff[index++] = 0x06;
		app5_send_buff[index++] = (reg_addr >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_addr >> 0) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 8) & 0x00ff;
		app5_send_buff[index++] = (reg_numb >> 0) & 0x00ff;
		crc_code = count_crc16(app5_send_buff, index);
		app5_send_buff[index++] = (crc_code >> 8) & 0x00ff;
		app5_send_buff[index++] = crc_code & 0x00ff;
		DRV_USART0_Send(app5_send_buff, index);
		pcf8575_led_toggle(LED_LO_05);
	}


	return ;
}		/* -----  end of function fun_06_analy  ----- */

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  fun_10_analy
 *  Description:
 * =====================================================================================
 */
void fun_10_analy(uint16_t chn, uint8_t *buff, uint16_t size) {

    uint16_t i;
    uint16_t index = 0;
    uint16_t data;
    uint16_t crc_code = 0;
    uint16_t addr = ((buff[2] << 8) & 0xff00) + buff[3];
    uint16_t numb = ((buff[4] << 8) & 0xff00) + buff[5];
    //	uint8_t byte_count = buff[6];

    if ((addr == 0x7500) && (numb == 0x0002)) {
        //		device_save_reboot();
        save_cfg_para(0x01);
    }
   
    if ((addr >= CFG_TBL_START_ADDR) && ((addr + numb) <= (CFG_TBL_END_ADDR + 1))) {
        for (i = 0; i < numb; i += 1) {
            data = ((buff[i * 2 + 7] << 8) & 0xff00) + buff[i * 2 + 8];
            cfg_tbl[addr - CFG_TBL_START_ADDR + i] = data;
        }
	load_motor_cfg_tbl();
        app5_send_buff[index++] = 0x01;
        app5_send_buff[index++] = 0x10;
        app5_send_buff[index++] = (addr >> 8) & 0x00ff;
        app5_send_buff[index++] = (addr >> 0) & 0x00ff;
        app5_send_buff[index++] = (numb >> 8) & 0x00ff;
        app5_send_buff[index++] = (numb >> 0) & 0x00ff;
        crc_code = count_crc16(app5_send_buff, index);
        app5_send_buff[index++] = (crc_code >> 8) & 0x00ff;
        app5_send_buff[index++] = crc_code & 0x00ff;
        DRV_USART0_Send(app5_send_buff, index);
        pcf8575_led_toggle(LED_LO_05);
        //                switch(chn){
        //                    case 0:
        //                        DRV_USART0_Send(app5_send_buff, index);
        //                        break;
        //                    case 1:
        //                         DRV_USART1_Send(app5_send_buff, index);
        //                        break;
        //                }
    } else {

    }

    return;
} /* -----  end of function fun_10_analy  ----- */

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  recv_cfg_analy
 *  Description:  接收到数据解析。
 * =====================================================================================
 */
uint8_t recv_cfg_analy(uint16_t chn, uint8_t *data, uint16_t size) {

    uint8_t slave;
    uint8_t fun_code;
    uint16_t reg_addr;
    uint16_t reg_numb;
    uint16_t crc_code;

    slave = data[0];
    fun_code = data[1];
    reg_addr = (data[2] << 8) + data[3];
    reg_numb = (data[4] << 8) + data[5];
    crc_code = (data[6] << 8) + data[7];

        if(slave != 0x01){
            return false;
        }

    switch (fun_code) {
        case 0x03:
            fun_03_analy(chn, reg_addr, reg_numb);
            break;
        case 0x05:
            fun_05_analy(chn, reg_addr, reg_numb);
            break;
        case 0x06:
            fun_06_analy(chn, reg_addr, reg_numb);
            break;
        case 0x10:
            fun_10_analy(chn, data, size);
            break;
        default:
            return false;
            //			break;
    } /* -----  end switch  ----- */

    return true;
} /* -----  end of function recv_cfg_analy  ----- */

// *****************************************************************************
// *****************************************************************************
// Section: Application Initialization and State Machine Functions
// *****************************************************************************
// *****************************************************************************

/*******************************************************************************
  Function:
    void APP5_Initialize ( void )

  Remarks:
    See prototype in app5.h.
 */

void APP5_Initialize(void) {
    /* Place the App state machine in its initial state. */
    app5Data.state = APP5_STATE_INIT;

    /* TODO: Initialize your application's state machine and other
     * parameters.
     */
}

//函数功能：延时函数
void delay_W5100(uint32_t num)
{
	uint32_t i;
	for(i=0;i<num;i++)
	{asm("nop");}
	return;
}

void bootloader_state_check(uint8_t *data, uint16_t recv_size){

	uint8_t ret;
	uint16_t i = 0;
	
	uint16_t buf_config[10] = {0};

	
	if(recv_size == (0x0f-8)){ /*如果接收到长度等于UDP接收的升级程序第一帧长度。*/
		if((data[0] == 0x01) && (data[6] == 0x04) && (data[4] == 0x10) && (data[5] == 0x10)){

			bootloader_save_buff[0] = 0xff00; /*IP地址*/ 
			bootloader_save_buff[1] = 0x00ff;
			bootloader_save_buff[2] = 0xff00; /*网关*/ 
			bootloader_save_buff[3] = 0x00ff;
			bootloader_save_buff[4] = 0xff00; /*子网掩码*/ 
			bootloader_save_buff[5] = 0x00ff;
			bootloader_save_buff[6] = 0xff00; /*升级程序标志位。*/
			
			ret = NVMErasePage((void*) (0x1d030000 | 0xa0000000));
			for (i = 0; i < 10; i++) {
				ret = NVMWriteWord((void*) ((0x1d030000 | 0xa0000000) + i * 4), bootloader_save_buff[i]);
				if (ret != 0) {
//					printf("Save Param Error![addr = %ld]\r\n", ((0x1d07f000 | 0xa0000000) + i * 4));
				}
			}
//			printf("Save Param Finish, Reset Now!!!\r\n");
//			for(i=0;i<10;i++){
//				buf_config[i] = NVMReadWord((void*)((0x1d030000 | 0xa0000000) + i*4));
//			}
			SoftReset();//软件复位
		}
	}
	if(recv_size == (0x0d-8)){
		if((data[0] == 0x01) && (data[1] == 0x02)){
			bootloader_save_buff[0] = 0;
			bootloader_save_buff[1] = 0;
			bootloader_save_buff[2] = 0;
			bootloader_save_buff[3] = 0;
			bootloader_save_buff[4] = 0;
			bootloader_save_buff[5] = 0;
			bootloader_save_buff[6] = 0xff00; /*升级程序标志位。*/

			while(i<100){
				NVMErasePage((void*)(0x9D005000));
				delay_W5100(1000);
				ret = NVMWriteRow((void*)0x9D005000, bootloader_save_buff);
				if(ret != 0){
					i++;
				}else{
					break;
				}
			}
			SoftReset();//软件复位
		}
	}	
}

/******************************************************************************
  Function:
    void APP5_Tasks ( void )

  Remarks:
    See prototype in app5.h.
 */

void APP5_Tasks(void) {
    uint8_t ret;
    /* Check the application's current state. */
    switch (app5Data.state) {
            /* Application's initial state. */
        case APP5_STATE_INIT:
        {
//            para_temp();      //临时函数，用于AI校准
            ret = DRV_USART0_Recv(app5_recv_buff, 0);
            if (ret > 0) {
		bootloader_state_check(app5_recv_buff, ret);
//                pcf8575_led_toggle(LED_LO_05);
                recv_cfg_analy(1, app5_recv_buff, ret);
                //                DRV_USART0_Send(app5_recv_buff, ret);
            }
            //                PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
            //                printf("RS-485 reserve task!\r\n");
            //                PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
            break;
        }

            /* TODO: implement your application state machine.*/

            /* The default state should never be executed. */
        default:
        {
            /* TODO: Handle error in application's state machine. */
            break;
        }
    }
}


/*******************************************************************************
 End of File
 */
